#include "game_string.h"
#include <assert.h>
#include <algorithm>

BOOL __string_startwith(const std::string &src,std::string &val){
  return src.compare(0, val.size(), val) == 0 ? TRUE:FALSE;
}

BOOL __string_startwith(const std::string &src,const char* val){
  std::string str{val};
  return __string_startwith(src,str);
}
BOOL __string_endwith(const std::string src, const std::string val) {
  return src.rfind(val) == (src.length() - val.length());
}
BOOL __string_endwith(const std::string src, const char* val) {
  std::string str{val};
  return __string_endwith(src,str);
}
BOOL __is_empty_string(const char* v){
  return NULL == v || 0 == strlen(v) ? TRUE:FALSE;
}


/*--- This a C++ universal sprintf in the future.
**  @pitfall: The behavior of vsnprintf between VS2013 and VS2015/2017 is different
**      VS2013 or Unix-Like System will return -1 when buffer not enough, but VS2015/2017 will return the actural needed length for buffer at this station
**      The _vsnprintf behavior is compatible API which always return -1 when buffer isn't enough at VS2013/2015/2017
**      Yes, The vsnprintf is more efficient implemented by MSVC 19.0 or later, AND it's also standard-compliant, see reference: http://www.cplusplus.com/reference/cstdio/vsnprintf/
*/
std::string __string_format(const char *format, ...)
{
  va_list args;
  std::string buffer(C_VSNPRINTF_BUFFER_LENGTH, '\0');

  va_start(args, format);
  int nret = vsnprintf(&buffer.front(), buffer.length() + 1, format, args);
  va_end(args);

  if (nret >= 0)
  {
    if ((unsigned int)nret < buffer.length())
    {
      buffer.resize(nret);
    }
    else if ((unsigned int)nret > buffer.length())
    { // VS2015/2017 or later Visual Studio Version
      buffer.resize(nret);

      va_start(args, format);
      nret = vsnprintf(&buffer.front(), buffer.length() + 1, format, args);
      va_end(args);

      assert(nret == (int)buffer.length());
    }
    // else equals, do nothing.
  }
  else
  { // less or equal VS2013 and Unix System glibc implement.
    do
    {
      buffer.resize(buffer.length() * 3 / 2);

      va_start(args, format);
      nret = vsnprintf(&buffer.front(), buffer.length() + 1, format, args);
      va_end(args);

    } while (nret < 0);

    buffer.resize(nret);
  }

  return buffer;
}

std::vector<std::string> __string_split(const std::string &string, const std::string &delim)
{
  std::vector<std::string> result;
  size_t from = 0, to = 0;
  while (std::string::npos != (to = string.find(delim, from))) {
    result.push_back(string.substr(from, to - from));
    from = to + delim.length();
  }
  result.push_back(string.substr(from, to));
  return result;
}

std::string __string_join(const std::vector<std::string>& vec,const std::string& delim){
  if(vec.empty())
    return "";
  else if(1 == vec.size()){
    return vec.at(0);
  }else{
    std::string str;
    std::vector<std::string>::const_iterator last = vec.end() - 1;
    for(std::vector<std::string>::const_iterator itr = vec.begin();itr != vec.end();itr ++){
      str += *itr;
      if(itr != last){
        str += delim;
      }
    }
    return str;
  }
}

void __string_to_lower_case(std::string &str)
{
  std::transform(str.begin(), str.end(), str.begin(), ::tolower);
}

void __string_to_upper_case(std::string &str)
{
  std::transform(str.begin(), str.end(), str.begin(), ::toupper);
}

void __string_trim(char *str)
{
  std::string tmp(str);
  __string_trim(tmp);
  strcpy(str,tmp.c_str());
}

void __string_trim(std::string &str)
{
    // 移除前导空格
    str.erase(str.begin(), std::find_if(str.begin(), str.end(), std::not1(std::ptr_fun<int, int>(std::isspace))));

    // 移除尾部空格
    str.erase(std::find_if(str.rbegin(), str.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), str.end());
}
